package modules.java8.stream2;

import modules.dao.UserRepository;
import modules.entities.User;
import org.junit.jupiter.api.Test;
import org.junit.platform.commons.util.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.time.Duration;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
import java.util.stream.Stream;

/**
 * Stream流式计算 1
 *      创建流
 *      筛选 / 切片  重复
 *      映射
 *      并行流 - 串行流
 *
 * @author shengren.yan
 * @create 2021-03-15
 */
@SpringBootTest
public class Stream1 {

    @Autowired
    UserRepository userRepository;

    // 创建流
    @Test
    void test() {
        // 1.可以通过 Collection 系列集合提供的stream()或parallelStream()
        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();

        // 2.通过 Arrays 中的静态方法stream()获取数组流
        User[] emps = new User[10];
        Stream<User> stream2 = Arrays.stream(emps);

        // 3.通过Stream 类中的静态方法of()
        Stream<String> stream3 = Stream.of("aa","bb","cc");

        // 4.创建无限流  -- 迭代
        Stream<Integer> stream4 = Stream.iterate(0, (x) -> x+2);
        //stream4.limit(10).forEach(System.out::println);

        // 生成无限的流，截取前5个
        Stream.generate(() -> Math.random()).limit(5).forEach(System.out::println);

    }

    // 筛选 / 切片
    @Test
    void test1() {

        List<User> list = userRepository.findAll();
//        list.forEach(System.out::println);

        //筛选 filter
//        System.out.println("----------- filter 过滤 -------------");
//        List<User> collect = list.stream().filter((x) -> {
//            return x.getGender() == 1;
//        }).collect(Collectors.toList());
//        collect.forEach(System.out::println);
//        // 简写
//        list.stream().filter(x->x.getGender()==1).collect(Collectors.toList());


        //取前两条数据 limit
//        System.out.println("----------- 取前两条数据 -------------");
//        list.stream().limit(2).forEach(System.out::println);

        //跳过四条数据  skip
//        System.out.println("----------- 跳过四条数据 -------------");
//        list.stream().skip(4).forEach(System.out::println);

        //去重复 distinct  ,需要重写hashCode() 和 equals
        //了解了HashMap的实现方式。HashMap先根据hashcode方法定位，再比较equals方法。
        //所以，要使用distinct来实现去重，必须重写hashcode和equals方法，除非你使用默认的。
//        System.out.println("----------- 去重复 -------------");
//        User user1 = new User();
//        user1.setId(29);
//        user1.setUsername("蚂蚁");
//        User user2 = new User();
//        user2.setId(29);
//        user2.setUsername("蚂蚁");
//        list.add(user1);
//        list.add(user2);
//        list.stream().forEach(System.out::println);
//        System.out.println("----------- 去重复 -------------");
//        list.stream().distinct().forEach(System.out::println);

        //去重 - 姓名重复的人
        //计算部分就是把 Stream的元素拿出来和我自己内置的一个HashMap比较，有则跳过，没有则放进去。
//        System.out.println("----------- 去重 - 姓名重复的人 -------------");
//        User user2 = new User();
//        user2.setId(29);
//        user2.setUsername("蚂蚁");
//        list.add(user2);
//        User user3 = new User();
//        user3.setId(30);
//        user3.setUsername("蚂蚁");
//        list.add(user3);
//        list.stream().forEach(System.out::println);
//        System.out.println("----------- 去重 - 姓名重复的人 -------------");
//        list.stream().filter(distinctByVariable(User::getUsername))
//                .forEach(fu -> System.out.println(fu.toString()));

        // 筛选重复多个字段数据
//        list = list.stream().collect(
//                Collectors.collectingAndThen(
//                        Collectors.toCollection(() -> new TreeSet<>(
//                                Comparator.comparing(p->p.getUserType() + ";" + p.getGender())
//                        )), ArrayList::new));
//        list.forEach(System.out::println);

    }

    /* putIfAbsent() 方法是
     *    如果 key对应的value值不存在, key value 添加到 map 中,并返回 null
     *    如果 key对应的value值已存在, key value 不再添加到 map 中, 并返回原 value
    */
    private static <T> Predicate<T> distinctByVariable(Function<? super T, ?> keyExtractor) {
//        Set<Object> seen = ConcurrentHashMap.newKeySet();
//        return t -> seen.add(keyExtractor.apply(t));
        HashMap<Object, Boolean> map = new HashMap<>();
        return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }


    // 映射
    @Test
    void test2() {
        List<String> list = Arrays.asList("aaa", "bbb", "ccc");
        // 将集合里的字符串变成大写
        List<String> collect = list.stream().map((x) -> {
            return x.toUpperCase();
        }).collect(Collectors.toList());
        collect.forEach(System.out::println);
        //简写
        list.stream().map(String::toUpperCase).forEach(System.out::println);
    }

    // 并行流 - 串行流
    @Test
    void test3() {
        // 将大任务拆分小任务  Fork / join
        Instant i = Instant.now();
        // 并行流  parallel()   .sequential()  顺序流
        long reduce = LongStream.rangeClosed(0, 1000000L)
                .parallel()
                .reduce(0, Long::sum);
        System.out.println(reduce);

        long duration = Duration.between(i, Instant.now()).toMillis();
        System.out.println("时间" + duration);
    }

    // 讲list切分成 , 的字符串
    @Test
    void test4(){
        List<String> list= Arrays.asList("aaa",  "", "ccc", "ddd");
        String str= String.join(",", list);
        System.out.println(str);
    }


}
